package com.liuzy.tool;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * JSON工具-依赖org.json-2.0.jar
 * <pre> 有这样一个字符串：
 * {"context":"一级","data":[{"context":"二级","data":[{"context":"三级","data":""}]}]}
 * JSON json = new JSON(string);
 * json.get("context").value();
 * json.getArray("data", 0).get("context").value();
 * json.getArray("data", 0).getArray("data", 0).get("context").value();</pre>
 * @author liuzy
 * @since 2015年10月18日
 */
public class JSON {
	private String jsonStr;
	private JSONObject jsonObj;
	private Object[] obj = new Object[10];
	private String[] value = new String[10];
	private static int index = 0;
	/** */
	public JSON(String jsonStr) throws JSONException {
		this.jsonStr = jsonStr;
		this.jsonObj = new JSONObject(jsonStr);
	}
	/** 获取key对应的"" */
	public JSON get(String key) throws JSONException {
		if (index == 0)
			try {
				obj[index] = jsonObj.getJSONObject(key);
			} catch (Exception e) {
				obj[index] = jsonObj.getString(key);
			}
		else
			try {
				obj[index] = ((JSONObject) obj[index - 1]).getJSONObject(key);
			} catch (Exception e) {
				obj[index] = ((JSONObject) obj[index - 1]).getString(key);
			}
		value[index] = obj[index].toString();
		index++;
		return this;
	}
	/** 获取key对应[] */
	public JSON getArray(String key) throws JSONException {
		if (index == 0)
			obj[index] = jsonObj.getJSONArray(key);
		else
			obj[index] = ((JSONObject) obj[index - 1]).getJSONArray(key);
		value[index] = obj[index].toString();
		index++;
		return this;
	}
	/** 获取key对应[]的第i个{} */
	public JSON getArray(String key, int i) throws JSONException {
		if (index == 0)
			obj[index] = jsonObj.getJSONArray(key).get(0);
		else
			obj[index] = ((JSONObject) obj[index - 1]).getJSONArray(key).get(i);
		value[index] = obj[index].toString();
		index++;
		return this;
	}
	/** 取当前值 */
	public String value() {
		String v = value[index - 1];
		index = 0;
		return v;
	}
	/** 格式化json输出 */
	@Override
	public String toString() {
		return formatJson(jsonStr);
	}
	/** 对象转json字符串 */
	public static String toJson(Object obj) {
		return new JSONObject(obj).toString();
	}
	/** 对象转格式化json字符串 */
	public static String toFormatJson(Object obj) {
		return formatJson(new JSONObject(obj).toString());
	}
	/** json字符串转对象 */
	public static <T> T formJson(Class<T> clazz, String jsonStr) {
		T obj = null;
		try {
			obj = clazz.newInstance();
			Map<String, String> map = new HashMap<>();
			JSONObject jsonObject = new JSONObject(jsonStr);
			Iterator<?> iterator = jsonObject.keys();
			while (iterator.hasNext()) {
				String key = (String) iterator.next();
				String value = jsonObject.getString(key);
				map.put(key, value);
			}
			Method[] methods = obj.getClass().getDeclaredMethods();
			for (Method method : methods) {
				try {
					String field = method.getName();
					if (field.startsWith("set")) {
						field = field.substring(field.indexOf("set") + 3);
						field = field.toLowerCase().charAt(0) + field.substring(1);
						method.invoke(obj, new Object[]{map.get(field)});
					}
				} catch (Exception e) {
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return obj;
	}
	/** 格式化json */
	public static String formatJson(String jsonStr) {
		return formatJson(jsonStr, "  ");
	}
	/** 格式化json */
	public static String formatJson(String jsonStr, String fillStringUnit) {
		if (jsonStr == null || jsonStr.trim().isEmpty()) {
			return null;
		}
		int fixedLenth = 0;
		ArrayList<String> tokenList = new ArrayList<String>();
		{
			String jsonTemp = jsonStr;
			while (jsonTemp.length() > 0) {
				String token = getToken(jsonTemp);
				jsonTemp = jsonTemp.substring(token.length());
				token = token.trim();
				tokenList.add(token);
			}
		}
		for (int i = 0; i < tokenList.size(); i++) {
			String token = tokenList.get(i);
			int length = token.getBytes().length;
			if (length > fixedLenth && i < tokenList.size() - 1 && ":".equals(tokenList.get(i + 1))) {
				fixedLenth = length;
			}
		}
		StringBuilder buf = new StringBuilder();
		int count = 0;
		for (int i = 0; i < tokenList.size(); i++) {
			String token = tokenList.get(i);
			if (",".equals(token)) {
				buf.append(token);
				doFill(buf, count, fillStringUnit);
				continue;
			}
			if (":".equals(token)) {
				buf.append(" ").append(token).append(" ");
				continue;
			}
			if ("{".equals(token)) {
				String nextToken = tokenList.get(i + 1);
				if ("}".equals(nextToken)) {
					i++;
					buf.append("{ }");
				} else {
					count++;
					buf.append(token);
					doFill(buf, count, fillStringUnit);
				}
				continue;
			}
			if ("}".equals(token)) {
				count--;
				doFill(buf, count, fillStringUnit);
				buf.append(token);
				continue;
			}
			if ("[".equals(token)) {
				String nextToken = tokenList.get(i + 1);
				if ("]".equals(nextToken)) {
					i++;
					buf.append("[ ]");
				} else {
					count++;
					buf.append(token);
					doFill(buf, count, fillStringUnit);
				}
				continue;
			}
			if ("]".equals(token)) {
				count--;
				doFill(buf, count, fillStringUnit);
				buf.append(token);
				continue;
			}
			buf.append(token);
			if (i < tokenList.size() - 1 && ":".equals(tokenList.get(i + 1))) {
				int fillLength = fixedLenth - token.getBytes().length;
				if (fillLength > 0) {
					for (int j = 0; j < fillLength; j++) {
						buf.append(" ");
					}
				}
			}
		}
		return buf.toString();
	}

	private static String getToken(String jonStr) {
		StringBuilder buf = new StringBuilder();
		boolean isInYinHao = false;
		while (jonStr.length() > 0) {
			String token = jonStr.substring(0, 1);
			jonStr = jonStr.substring(1);
			if (!isInYinHao && (":".equals(token) || "{".equals(token) || "}".equals(token) || "[".equals(token) || "]".equals(token) || ",".equals(token))) {
				if (buf.toString().trim().length() == 0) {
					buf.append(token);
				}
				break;
			}
			if ("\\".equals(token)) {
				buf.append(token);
				buf.append(jonStr.substring(0, 1));
				jonStr = jonStr.substring(1);
				continue;
			}
			if ("\"".equals(token)) {
				buf.append(token);
				if (isInYinHao) {
					break;
				} else {
					isInYinHao = true;
					continue;
				}
			}
			buf.append(token);
		}
		return buf.toString();
	}

	private static void doFill(StringBuilder buf, int count, String fillStringUnit) {
		buf.append("\n");
		for (int i = 0; i < count; i++) {
			buf.append(fillStringUnit);
		}
	}

}
